home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / MISC / DTMFF110 / SC_SB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-05  |  8.8 KB  |  359 lines

  1. /*
  2.  *  Routines for sampling from Soundblaster 8-bit soundcards
  3.  *  These routines require the SB functions and DMA functions written
  4.  *  by Heath I. Hunnicutt.  The required functions are included here.
  5.  *  Copyright (C) 1997    Philip VanBaren & Emil Laurentiu
  6.  *  Last modified: Wednesday, 06 August 1997
  7.  */
  8.  
  9. #include "freq.h"
  10.  
  11. #ifdef SC_SB8
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <math.h>
  16. #include <dos.h>
  17. #include <graphics.h>
  18. #include "sb.h"
  19. #include "sbio.h"
  20. #include "extern.h"
  21.  
  22. /* Function prototypes */
  23. unsigned int  sbpro_get_line_level( void );
  24. unsigned int  sbpro_get_cd_level( void );
  25. unsigned int  sbpro_get_mic_level( void );
  26. int          atox( char *ptr );
  27. void far interrupt SBHandler( void );
  28. void          init_sb8( char **environ );
  29. void          reset_sb8( void );
  30. void          halt_sb8( void );
  31. void          cleanup_sb8( void );
  32. void          recordblock_sb8( void far * buffer );
  33. void          set_mixer_sb8( int mix, int level );
  34.  
  35. unsigned int
  36. sbpro_get_line_level( void )
  37. {
  38.   unsigned int    val;
  39.  
  40.   outportb( sb_addr + 4, 0x2E );
  41.   val = inportb( sb_addr + 5 );
  42.   return ( ( ( val & 0x0F ) + ( val / 16 ) ) * 100 / 32 );
  43. }
  44.  
  45. unsigned int
  46. sbpro_get_cd_level( void )
  47. {
  48.   unsigned int    val;
  49.  
  50.   outportb( sb_addr + 4, 0x28 );
  51.   val = inportb( sb_addr + 5 );
  52.   return ( ( ( val & 0x0F ) + ( val / 16 ) ) * 100 / 32 );
  53. }
  54.  
  55. unsigned int
  56. sbpro_get_mic_level( void )
  57. {
  58.   unsigned int    val;
  59.  
  60.   outportb( sb_addr + 4, 0x0A );
  61.   val = inportb( sb_addr + 5 );
  62.   return ( ( val & 0x07 ) * 100 / 8 );
  63. }
  64.  
  65. int
  66. atox( char *ptr )
  67. {
  68.   // Convert ascii hex values to integer
  69.   int        v = 0;
  70.  
  71.   while ( ( ( *ptr >= '0' ) && ( *ptr <= '9' ) ) || ( ( ( *ptr | 0x20 ) >= 'a' ) && ( ( *ptr | 0x20 ) <= 'f' ) ) )
  72.   {
  73.     v = v * 16;
  74.     if ( *ptr <= '9' )
  75.       v = v + *ptr - '0';
  76.     else
  77.       v = v + ( *ptr | 0x20 ) - 'a' + 10;
  78.     ptr++;
  79.   }
  80.   return v;
  81. }
  82.  
  83. #define is_blaster(var) ((((var)[0]=='B')||((var)[0]=='b')) && \
  84.              (((var)[1]=='L')||((var)[1]=='l')) && \
  85.              (((var)[2]=='A')||((var)[2]=='a')) && \
  86.              (((var)[3]=='S')||((var)[3]=='s')) && \
  87.              (((var)[4]=='T')||((var)[4]=='t')) && \
  88.              (((var)[5]=='E')||((var)[5]=='e')) && \
  89.              (((var)[6]=='R')||((var)[6]=='r')))
  90.  
  91. void far      interrupt( *OldIRQ ) (  );
  92.  
  93. /* Interrupt handler for DMA complete IRQ from Soundblaster */
  94. void far      interrupt
  95. SBHandler(  )
  96. {
  97.   flag[record_buffer] = 1;
  98.   if ( ++record_buffer >= BUFFERS )
  99.     record_buffer = 0;
  100.   inportb( DSP_DATA_AVAIL );
  101.   outportb( 0x20, 0x20 );
  102. }
  103.  
  104. void
  105. init_sb8( char **environ )
  106. {
  107.   int        i;
  108.   unsigned char tm, im;
  109.   long        timeout;
  110.  
  111.   /* Scan the environment variables for BLASTER=Axxx Ix Dx */
  112.   for ( i = 0; environ[i] != NULL; i++ )
  113.   {
  114.     if ( is_blaster( environ[i] ) )
  115.     {
  116.       int        j;
  117.       DOUT( "SB8: Found BLASTER environment variable." );
  118.       for ( j = 8; environ[i][j] != 0; j++ )
  119.       {
  120.     if ( ( environ[i][j] == 'A' ) || ( environ[i][j] == 'a' ) )
  121.       sb_addr = atox( &environ[i][j + 1] );
  122.     if ( ( environ[i][j] == 'D' ) || ( environ[i][j] == 'd' ) )
  123.       sb_dma = atoi( &environ[i][j + 1] );
  124.     if ( ( environ[i][j] == 'I' ) || ( environ[i][j] == 'i' ) )
  125.       sb_irq = atoi( &environ[i][j + 1] );
  126.     // Skip to the next parameter
  127.     while ( ( environ[i][j] != ' ' ) && ( environ[i][j + 1] != 0 ) )
  128.       j++;
  129.       }
  130.       break;
  131.     }
  132.   }
  133. #ifdef DEBUG_OUTPUT
  134.   {
  135.     char      message[100];
  136.     sprintf( message, "SB8: Address=0x%03x, DMA=%d, IRQ=%d", sb_addr, sb_dma, sb_irq );
  137.     DOUT( message );
  138.   }
  139. #endif
  140.  
  141.   if ( ( sb_dma < 0 ) || ( sb_dma > 3 ) )
  142.   {
  143.     puts( "Only SB DMA channels up to 3 are supported." );
  144.     exit( 1 );
  145.   }
  146.   if ( ( sb_irq < 1 ) || ( sb_irq > 7 ) )
  147.   {
  148.     puts( "Only SB IRQs up to 7 are supported." );
  149.     exit( 1 );
  150.   }
  151.   reset_soundcard = reset_sb8;
  152.   halt_soundcard = halt_sb8;
  153.   cleanup_soundcard = cleanup_sb8;
  154.   recordblock = recordblock_sb8;
  155.   sample_size = 8;
  156.   mixers = 0;
  157.  
  158.   set_SB_address( sb_addr );
  159. #ifndef DEBUG_MODE
  160.   if ( !dsp_reset(  ) )
  161.   {
  162.     closegraph(     );
  163.     printf( "Soundblaster not found at 0x%04x\n", sb_addr );
  164.     exit( 1 );
  165.   }
  166.   dsp_voice( 0 );
  167.  
  168.   /* Check if we can do mixers, and enable them, if so */
  169.   timeout = 1000000L;
  170.   /* Wait for bit 7 to be cleared, or for a timeout */
  171.   while ( ( inportb( sb_addr + 0x0E ) & 0x80 ) && ( --timeout ) );
  172.   outportb( sb_addr + 0x0C, 0xE1 );    /* Get DSP version number */
  173.   timeout = 1000000L;
  174.   /* Wait for bit 7 to be set, or for a timeout */
  175.   while ( ( !( inportb( sb_addr + 0x0E ) & 0x80 ) ) && ( --timeout ) );
  176.   i = inportb( sb_addr + 0x0A );/* Get the major version number */
  177.   while ( ( !( inportb( sb_addr + 0x0E ) & 0x80 ) ) && ( --timeout ) );
  178.   inportb( sb_addr + 0x0A );    /* Get the major version number */
  179.  
  180.   if ( i > 2 )
  181.   {
  182.     DOUT( "SB8: Found an SBPro or greater, mixers are available" );
  183.     mixers = 1;
  184.     set_mixer = set_mixer_sb8;
  185.     mic_level = sbpro_get_mic_level(  );
  186.     ext_level = sbpro_get_line_level(  );
  187.     int_level = sbpro_get_cd_level(  );
  188.     DOUT( "SB8: Set Master volume & FM volume to maximum" );
  189.     set_master_level( 0x0f );
  190.     set_fm_level( 0x0f );
  191.   }
  192.  
  193.   /*
  194.    * Add the SB DMA interrupt handler in the interrupt chain
  195.    */
  196.   disable(  );
  197.   OldIRQ = getvect( 0x08 + sb_irq );
  198.   setvect( 0x08 + sb_irq, SBHandler );
  199.   im = inportb( 0x21 );
  200.   tm = ~( 1 << sb_irq );
  201.   outportb( 0x21, im & tm );
  202.   enable(  );
  203. #endif
  204. }
  205.  
  206. void
  207. reset_sb8( void )
  208. {
  209.   /*
  210.    * Initialize Soundblaster stuff
  211.    */
  212.   int        i, dsp_tc;
  213.  
  214. #ifndef DEBUG_MODE
  215.   /* Round sampling rate to a valid value for the SB card */
  216.   i = floor( 1000000.0 / SampleRate + 0.5 );
  217.   if ( i < 1 )
  218.     i = 1;
  219.   SampleRate = floor( 1000000.0 / ( double ) i + 0.5 );
  220.   dsp_tc = 256 - i;
  221.  
  222.   DOUT( "SB8: Setting sampling rate" );
  223.   dsp_time( dsp_tc );
  224.  
  225.   /*
  226.    * Initialize the SB DMA channel
  227.    */
  228.   DOUT( "SB8: Resetting the DMA channel" );
  229.   if ( dma_reset( sb_dma ) )
  230.   {
  231.     closegraph(     );
  232.     puts( "Error resetting SB DMA channel." );
  233.     puts( dma_errlist[dma_errno] );
  234.     cleanup_sb8(  );
  235.     exit( 1 );
  236.   }
  237.   // Reset the buffer pointers
  238.   queue_buffer = 0;        // Pointer to next buffer to be queued
  239.   record_buffer = 0;        // Pointer to next buffer to be filled
  240.   process_buffer = 0;        // Pointer to next buffer to be FFTed
  241.  
  242.   for ( i = 0; i < BUFFERS; i++ )
  243.     flag[i] = 0;
  244.   /*
  245.    * This function starts the DMA process.
  246.    */
  247.   DOUT( "SB8: Starting the DMA recording process" );
  248.   recordblock_sb8( buffer[queue_buffer] );
  249.   if ( ++queue_buffer >= BUFFERS )
  250.     queue_buffer = 0;
  251. #endif
  252. }
  253.  
  254. void
  255. halt_sb8( void )
  256. {
  257. #ifndef DEBUG_MODE
  258.   /* Shut down the DMA transfers */
  259.   DOUT( "SB8: Stopping the DMA transfer" );
  260.   disable(  );
  261.   dma_reset( sb_dma );
  262.   dsp_reset(  );
  263.   enable(  );
  264. #endif
  265. }
  266.  
  267. void
  268. cleanup_sb8( void )
  269. {
  270.   // Clean up the soundcard routines
  271.  
  272.   unsigned char im, tm;
  273.  
  274. #ifndef DEBUG_MODE
  275.   DOUT( "SB8: Cleaning up the soundcard setup" );
  276.   disable(  );
  277.   dma_reset( sb_dma );
  278.   dsp_reset(  );
  279.   Sb_FM_Reset(    );
  280.   /* Restore old IRQ vector */
  281.   setvect( 0x08 + sb_irq, OldIRQ );
  282.   im = inportb( 0x21 );
  283.   tm = 1 << sb_irq;
  284.   outportb( 0x21, im | tm );
  285.   enable(  );
  286. #endif
  287. }
  288.  
  289. void
  290. recordblock_sb8( void far * buffer )
  291. {
  292. #ifndef DEBUG_MODE
  293.   /*
  294.    * Start recording a new buffer. For now we don't have queueing
  295.    * capabilities for the SB
  296.    */
  297.   if ( dma_setup( sb_dma, buffer, fftlen, 0 ) )
  298.   {
  299.     closegraph(     );
  300.     printf( "Error in dma_setup(): %d\n", dma_errno );
  301.     puts( dma_errlist[dma_errno] );
  302.     cleanup_sb8(  );
  303.     exit( 1 );
  304.   }
  305.   if ( dma_errno != 0 )
  306.   {
  307.     closegraph(     );
  308.     puts( "DMA error" );
  309.     puts( dma_errlist[dma_errno] );
  310.     cleanup_sb8(  );
  311.     exit( 1 );
  312.   }
  313.   dsp_dma_prepare( 0, fftlen );
  314. #endif
  315. }
  316.  
  317.  
  318. void
  319. set_mixer_sb8( int mix, int level )
  320. {
  321. #ifndef DEBUG_MODE
  322.   /*
  323.    * Set a mixer level on the PAS16 card
  324.    */
  325.   level = level * 16 / 100;
  326.   if ( level > 15 )
  327.     level = 15;
  328.  
  329.   if ( mix == MIXER_EXT )
  330.   {
  331.     DOUT( "SB8: Setting the line mixer level" );
  332.     level = level + level * 16;
  333.     outportb( sb_addr + 4, 0x2e );
  334.     outportb( sb_addr + 5, level );
  335.     outportb( sb_addr + 4, 0x0C );    /* Select the line input */
  336.     outportb( sb_addr + 5, 0x27 );
  337.   }
  338.   else if ( mix == MIXER_INT )
  339.   {
  340.     DOUT( "SB8: Setting the CD mixer level" );
  341.     level = level + level * 16;
  342.     outportb( sb_addr + 4, 0x28 );
  343.     outportb( sb_addr + 5, level );
  344.     outportb( sb_addr + 4, 0x0C );    /* Select the CD input */
  345.     outportb( sb_addr + 5, 0x23 );
  346.   }
  347.   else if ( mix == MIXER_MIC )
  348.   {
  349.     DOUT( "SB8: Setting the microphone mixer level" );
  350.     outportb( sb_addr + 4, 0x0a );
  351.     outportb( sb_addr + 5, level / 2 );
  352.     outportb( sb_addr + 4, 0x0C );    /* Select the mic input */
  353.     outportb( sb_addr + 5, 0x21 );
  354.   }
  355. #endif
  356. }
  357.  
  358. #endif
  359.